#include "SPInput.h"

namespace SP
{
	namespace
	{

		DIOBJECTDATAFORMAT g_aObjectFormats[] =
		{
			{ &GUID_XAxis, FIELD_OFFSET( SPInput::MouseState, lAxisX ),    // X axis
			DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
			{ &GUID_YAxis, FIELD_OFFSET( SPInput::MouseState, lAxisY ),    // Y axis
			DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
			{ 0, FIELD_OFFSET( SPInput::MouseState, abButtons[0] ),        // Button 0
			DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
			{ 0, FIELD_OFFSET( SPInput::MouseState, abButtons[1] ),        // Button 1 (optional)
			DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
			{ 0, FIELD_OFFSET( SPInput::MouseState, abButtons[2] ),        // Button 2 (optional)
			DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 }
		};
		
		#define numMouseObjects (sizeof(g_aObjectFormats) / sizeof(DIOBJECTDATAFORMAT))

		DIDATAFORMAT g_dfMouse =
		{
			sizeof( DIDATAFORMAT ),
			sizeof( DIOBJECTDATAFORMAT ),
			DIDF_ABSAXIS,
			sizeof( SPInput::MouseState ),
			numMouseObjects,
			g_aObjectFormats
		};
	}

	SPInput::SPInput( HWND hDlg )
	{
		HRESULT hr;

		m_bInitialized = false;

		// Register with the DirectInput subsystem and get a pointer
		// to a IDirectInput interface we can use.
		V( DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION,
			IID_IDirectInput8, ( VOID** )&m_pDI, NULL ) );
		  
		// Retrieve the system mouse
		V( m_pDI->CreateDevice( GUID_SysMouse, &m_pMouse, NULL ) );

		// A data format specifies which controls on a device we are interested in,
		// and how they should be reported. This tells DInput that we will be
		// passing a MouseState structure to IDirectInputDevice::GetDeviceState().
		V( m_pMouse->SetDataFormat( &g_dfMouse ) );

		// Set the cooperative level to let DInput know how this device should
		// interact with the system and with other DInput applications.
		V ( m_pMouse->SetCooperativeLevel( hDlg, DISCL_NONEXCLUSIVE |
			DISCL_FOREGROUND ) );

		m_hWnd = hDlg;
		m_bIsLeftDown = false;
		m_bIsRightDown = false;
		m_bIsMidDown = false;
	}

	SPInput::~SPInput()
	{
		if( m_pMouse )
			m_pMouse->Unacquire();

		SAFE_RELEASE( m_pMouse );
		SAFE_RELEASE( m_pDI );
	}

	HRESULT SPInput::Update()
	{
		// Poll the device to read the current state
		HRESULT hr = m_pMouse->Poll();
		if( FAILED( hr ) )
		{
			// DInput is telling us that the input stream has been
			// interrupted. We aren't tracking any state between polls, so
			// we don't have any special reset that needs to be done. We
			// just re-acquire and try again.
			hr = m_pMouse->Acquire();
			while( hr == DIERR_INPUTLOST )
				hr = m_pMouse->Acquire();

			// hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
			// may occur when the app is minimized or in the process of 
			// switching, so just try again later 
			return S_OK;
		}

		// Get the input's device state
		if( FAILED( hr = m_pMouse->GetDeviceState( sizeof( MouseState ), &m_MouseState ) ) )
			return hr; // The device should have been acquired during the Poll()

		// The initial mouse position should be subracted from the current point. 
		if( !m_bInitialized )
		{
			m_bInitialized = TRUE;
			m_LastXToSpace = m_pOrigin.x = m_MouseState.lAxisX;
			m_LastYToSpace = m_pOrigin.y = m_MouseState.lAxisY;
		}

		m_LastXToSpace = m_XToSpace;
		m_LastYToSpace = m_YToSpace;
		
		m_XToSpace = m_MouseState.lAxisX - m_pOrigin.x;
		m_YToSpace = m_MouseState.lAxisY - m_pOrigin.y;
		
		m_LastXToClient = m_XToClient;
		m_LastYToClient = m_YToClient;
		
		POINT pt;
		GetCursorPos(&pt); 
		HWND hWnd=WindowFromPoint(pt);
		if ( hWnd == m_hWnd )
		{
			ScreenToClient( hWnd, &pt ); 
			m_XToClient = pt.x;
			m_YToClient = pt.y;
		}

		m_bIsLeftDown = m_MouseState.abButtons[0] & 0x80;
		m_bIsRightDown = m_MouseState.abButtons[1] & 0x80;
		m_bIsMidDown = m_MouseState.abButtons[2] & 0x80;
	}
}